package com.lexc.watermq.broker.utils;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.security.AccessController;
import java.security.PrivilegedAction;

/**
 * createTime：2025-08-16 14:49
 * description：
 * 支持基于java的MMap api访问文件能力（文件的读写）
 * 支持指定的offset的文件映射（结束映射的offset-开始映射的offset=映射的内存体积）
 * 文件从指定的offset开始读取
 * 文件从指定的offset开始写入
 * 文件映射后的内存释放
 */
public class MMapUtil {

    private File file;
    private MappedByteBuffer mappedByteBuffer;
    private FileChannel fileChannel;

    /**
     * 指定offset做文件的映射
     *
     * @param filePath    文件路径
     * @param startOffset 读取的开始位置
     * @param mapSize     读取的大小(byte)
     */
    public void loadFileInMMap(String filePath, int startOffset, int mapSize) throws IOException {
        this.file = new File(filePath);
        if (!file.exists()) {
            throw new FileNotFoundException("file path " + filePath + " not exist");
        }
        RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");
        this.fileChannel = randomAccessFile.getChannel();

        this.mappedByteBuffer = this.fileChannel.map(FileChannel.MapMode.READ_WRITE,
                startOffset, mapSize);
    }

    /**
     * 文件从指定的offset开始读取
     *
     * @param readOffset:开始读取的位置
     * @param size：读取的大小
     * @return 读取到的内容_byte[]
     */
    public byte[] readContent(int readOffset, int size) {
        //直接定义读取的位置
        mappedByteBuffer.position(readOffset);
        byte[] content = new byte[size];
        int j = 0;
//        从内存中读取
        for (int i = 0; i < size; i++) {
            byte b = mappedByteBuffer.get(readOffset + i);
            content[j++] = b;
        }
        return content;
    }

    /**
     * 文件从指定的offset开始写入
     *
     * @param content 写入的内容
     * @param force   是否强制刷磁盘
     */
    public void writeContent(byte[] content, boolean force) {


        //默认刷新到page cache
        mappedByteBuffer.put(content);
        if (force) {
//强制刷入磁盘
            mappedByteBuffer.force();
        }
    }

    /**
     * 释放内存
     */
    public void clean() {
//        重置了position=0,
//        并没有清理内存
//        mappedByteBuffer.clear();
        if (mappedByteBuffer == null || !mappedByteBuffer.isDirect() || mappedByteBuffer.capacity() == 0) {
            return;
        }
        invoke(invoke(viewed(mappedByteBuffer), "cleaner"), "clean");
    }

    private Object invoke(final Object target, final String methodName, final Class<?>... clzs) {
        return AccessController.doPrivileged(new PrivilegedAction<Object>() {
            @Override
            public Object run() {
                try {
                    Method method = method(target, methodName, clzs);
                    method.setAccessible(true);
                    return method.invoke(target);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        });
    }

    private Method method(Object target, String methodName, Class<?>... clzs) throws NoSuchMethodException {
        try {
            return target.getClass().getMethod(methodName, clzs);
        } catch (NoSuchMethodException e) {
            return target.getClass().getDeclaredMethod(methodName, clzs);
        }
    }

    private ByteBuffer viewed(ByteBuffer buffer) {
        String methodName = "viewedBuffer";
        Method[] methods = buffer.getClass().getMethods();
        for (Method method : methods) {
//            获取到使用mapperBuffer的引用
            if (method.getName().equals("attachment")) {
                methodName = "attachment";
                break;
            }
        }

        ByteBuffer viewBuffer = (ByteBuffer) invoke(buffer, methodName);
        if (viewBuffer == null) {
            return buffer;
        } else {
            return viewBuffer;
        }
    }

//    public static void main(String[] args) throws InterruptedException, IOException {
//        Scanner input = new Scanner(System.in);
//        int i = 0;
//        long size = input.nextLong();
//        MMapUtil mMapUtil = new MMapUtil();//默认是字节
//
//        mMapUtil.loadFileInMMap("D:\\L.Info\\L.Application\\waterMQ\\waterMQ\\broker\\store\\order_cancel_topic\\111111111", 0, 10);
//        System.out.println("映射了" + size + "空间");
//
//        TimeUnit.SECONDS.sleep(10);
//        System.out.println("释放内存");
//        mMapUtil.clean();
//        TimeUnit.SECONDS.sleep(10000);
//    }

}
